package cn.anecansaitin.whimsy.common.capabilities.battle;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 拓展血量系统，添加了三种OW中的血量类型<br>
 * 护甲：可以减免受到的伤害<br>
 * 护盾：停止受到攻击后一段时间可以自动回复<br>
 * 临时血量：与原版伤害吸收类似
 */
public class ExpandedHP {
    private final HashMap<UUID, IHPInstance> temporary = new HashMap<>();
    private final HashMap<UUID, IHPInstance> armor = new HashMap<>();
    private final HashMap<UUID, IHPInstance> shield = new HashMap<>();
    /**
     * 护盾自动恢复所需的最大冷却时间
     */
    private final int maxShieldTick;
    /**
     * 护盾自动回复剩余的冷却时间，仅当不受到攻击时才会进行冷却
     */
    private int shieldTick = 0;
    /**
     * 护盾每tick恢复速率，默认0.15/tick
     */
    private final float shieldRecoverRate = 0.15f;
    private float totalTemporary = 0;
    private float totalArmor = 0;
    private float totalShield = 0;

    public ExpandedHP(int tickScaling) {
        maxShieldTick = 3 * 20 * tickScaling;
    }

    public void tick(int tick) {
        shieldTick = Math.max(0, shieldTick - tick);
        //临时变量，用来统计各个类型的生命值总和
        float t = 0f, a = 0f, s = 0f;

        if (!temporary.isEmpty()) {
            for (Map.Entry<UUID, IHPInstance> entry : temporary.entrySet()) {
                IHPInstance value = entry.getValue();
                value.tick(tick);

                if (value.needRemove()) {
                    temporary.remove(entry.getKey());
                } else {
                    t += value.amount();
                }
            }
        }

        if (!armor.isEmpty()) {
            for (Map.Entry<UUID, IHPInstance> entry : armor.entrySet()) {
                IHPInstance value = entry.getValue();
                value.tick(tick);

                if (value.needRemove()) {
                    armor.remove(entry.getKey());
                } else {
                    a += value.amount();
                }
            }
        }

        if (!shield.isEmpty()) {
            float recover = 0;

            if (canRecoverShield()) {
                recover = shieldRecoverRate;
            }

            for (Map.Entry<UUID, IHPInstance> entry : shield.entrySet()) {
                IHPInstance value = entry.getValue();
                value.tick(tick);

                if (value.needRemove()) {
                    shield.remove(entry.getKey());
                } else {
                    recover = value.heal(recover);
                    s += value.amount();
                }
            }
        }

        totalTemporary = t;
        totalArmor = a;
        totalShield = s;
    }

    public float hurt(float amount) {
        if (amount <= 0) {
            return 0;
        }

        shieldTick = maxShieldTick;

        //消耗临时生命
        for (IHPInstance value : temporary.values()) {
            amount = value.hurt(amount);

            if (amount < 0) {
                amount = 0;
                break;
            }
        }

        //消耗护甲
        if (amount <= 0) {
            return 0;
        }

        //存在护甲，则让将伤害降低为70%
        if (!armor.isEmpty()) {
            amount *= 0.7f;
        }

        for (IHPInstance value : armor.values()) {
            amount = value.hurt(amount);

            if (amount < 0) {
                amount = 0;
                break;
            }
        }

        //消耗护盾
        if (amount <= 0) {
            return 0;
        }

        for (IHPInstance value : shield.values()) {
            amount = value.hurt(amount);

            if (amount < 0) {
                amount = 0;
                break;
            }
        }

        return amount;
    }

    public float heal(float amount) {
        //恢复护盾
        for (IHPInstance value : shield.values()) {
            amount = value.heal(amount);

            if (amount < 0) {
                amount = 0;
                break;
            }
        }

        //恢复护甲
        if (amount <= 0) {
            return 0;
        }

        for (IHPInstance value : armor.values()) {
            amount = value.heal(amount);

            if (amount < 0) {
                amount = 0;
                break;
            }
        }

        return amount;
    }

    public void addTemporary(UUID uuid, IHPInstance hp) {
        temporary.put(uuid, hp);
    }

    public void addArmor(UUID uuid, IHPInstance hp) {
        armor.put(uuid, hp);
    }

    public void addShield(UUID uuid, IHPInstance hp) {
        shield.put(uuid, hp);
    }

    private boolean canRecoverShield() {
        return shieldTick <= 0;
    }

    public float getTotalHP() {
        return totalTemporary + totalArmor + totalShield;
    }

    public interface IHPInstance {
        default void tick(int tick) {
        }

        /**
         * @param amount 要抵挡的伤害值
         * @return 没能抵挡的伤害值
         */
        float hurt(float amount);

        /**
         * @param amount 要恢复的血量
         * @return 没能恢复的血量
         */
        float heal(float amount);

        /**
         * @return 当前血量
         */
        float amount();

        /**
         * @return 是否需要移除
         */
        boolean needRemove();
    }

    /**
     * 基础血量实现
     */
    public static class BaseHP implements IHPInstance {
        protected final float max;
        protected float amount;

        public BaseHP(float amount) {
            max = amount;
            this.amount = amount;
        }

        @Override
        public float hurt(float amount) {
            //伤害值小于等于0，无需伤害
            if (amount <= 0) {
                return 0;
            }

            //当前血量小于等于0，无需伤害
            if (this.amount <= 0) {
                return amount;
            }

            this.amount -= amount;

            if (this.amount < 0) {
                float v = this.amount;
                this.amount = 0;
                return -v;
            }

            return 0;
        }

        @Override
        public float heal(float amount) {
            //恢复值小于等于0，无需恢复
            if (amount <= 0) {
                return 0;
            }

            //已达上限，无需恢复
            if (this.amount >= max) {
                return amount;
            }

            this.amount += amount;

            if (this.amount > max) {
                float v = this.amount - max;
                this.amount = max;
                return v;
            }

            return 0;
        }

        @Override
        public float amount() {
            return amount;
        }

        @Override
        public boolean needRemove() {
            return false;
        }
    }

    /**
     * 基础护甲，减免受到的伤害，无限持续时间，用于基础血量
     */
    public static class Armor extends BaseHP {
        public Armor(float amount) {
            super(amount);
        }
    }

    /**
     * 基础护盾，无限持续时间，用于基础血量
     */
    public static class Shield extends BaseHP {
        public Shield(float amount) {
            super(amount);
        }
    }
}
